using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using WpfClient.Core.Communication;
using WpfClient.Core.Models;

namespace WpfClient.Infrastructure.Communication
{
    /// <summary>
    /// Socket通信服务实现
    /// </summary>
    public class SocketCommunicationService : ISocketCommunicationService, IDisposable
    {
        private readonly ISocketServer _socketServer;
        private readonly ILogger<SocketCommunicationService> _logger;
        private readonly ConcurrentQueue<QueuedMessage> _messageQueue = new();
        private readonly SemaphoreSlim _queueSemaphore = new(0);
        private CancellationTokenSource? _cancellationTokenSource;
        private Task? _processingTask;
        private bool _disposed;

        public bool IsRunning { get; private set; }
        public int ConnectedClientsCount => _socketServer.ConnectedClientsCount;

        public event EventHandler<ClientConnectedEventArgs>? ClientConnected;
        public event EventHandler<ClientDisconnectedEventArgs>? ClientDisconnected;
        public event EventHandler<CommunicationStatusEventArgs>? StatusChanged;

        public SocketCommunicationService(ISocketServer socketServer, ILogger<SocketCommunicationService> logger)
        {
            _socketServer = socketServer;
            _logger = logger;

            // 订阅Socket服务器事件
            _socketServer.ClientConnected += OnClientConnected;
            _socketServer.ClientDisconnected += OnClientDisconnected;
            _socketServer.DataSent += OnDataSent;
            _socketServer.DataReceived += OnDataReceived;
        }

        public async Task StartAsync(int port)
        {
            if (IsRunning)
            {
                _logger.LogWarning("通信服务已经在运行中");
                return;
            }

            try
            {
                _logger.LogInformation("正在启动Socket通信服务，端口: {Port}", port);

                _cancellationTokenSource = new CancellationTokenSource();
                
                // 启动Socket服务器
                await _socketServer.StartAsync(port, _cancellationTokenSource.Token);

                // 启动消息处理任务
                _processingTask = Task.Run(ProcessMessageQueueAsync, _cancellationTokenSource.Token);

                IsRunning = true;
                StatusChanged?.Invoke(this, new CommunicationStatusEventArgs("服务已启动", $"监听端口: {port}"));
                
                _logger.LogInformation("Socket通信服务启动成功");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "启动Socket通信服务失败");
                StatusChanged?.Invoke(this, new CommunicationStatusEventArgs("启动失败", ex.Message));
                throw;
            }
        }

        public async Task StopAsync()
        {
            if (!IsRunning)
            {
                _logger.LogWarning("通信服务未运行");
                return;
            }

            try
            {
                _logger.LogInformation("正在停止Socket通信服务...");

                IsRunning = false;
                _cancellationTokenSource?.Cancel();

                // 停止Socket服务器
                await _socketServer.StopAsync();

                // 等待消息处理任务完成
                if (_processingTask != null)
                {
                    await _processingTask;
                }

                _cancellationTokenSource?.Dispose();
                StatusChanged?.Invoke(this, new CommunicationStatusEventArgs("服务已停止"));
                
                _logger.LogInformation("Socket通信服务已停止");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "停止Socket通信服务时发生错误");
                StatusChanged?.Invoke(this, new CommunicationStatusEventArgs("停止失败", ex.Message));
            }
        }

        public async Task QueueDataAsync(string clientId, byte[] data)
        {
            if (!IsRunning)
            {
                _logger.LogWarning("通信服务未运行，无法发送数据");
                return;
            }

            var expectedResponse = GetExpectedResponse(data);
            var message = new QueuedMessage
            {
                ClientId = clientId,
                Data = data,
                ExpectedResponse = expectedResponse,
                QueuedAt = DateTime.UtcNow
            };

            _messageQueue.Enqueue(message);
            _queueSemaphore.Release();

            _logger.LogDebug("数据已加入发送队列: ClientId={ClientId}, Data={Data}", 
                clientId, Convert.ToHexString(data));

            await Task.CompletedTask;
        }

        public async Task QueueDataToAllAsync(byte[] data)
        {
            var clients = await GetConnectedClientsAsync();
            var tasks = clients.Select(client => QueueDataAsync(client.Id, data));
            await Task.WhenAll(tasks);
        }

        public async Task<IEnumerable<ClientInfo>> GetConnectedClientsAsync()
        {
            return await _socketServer.GetConnectedClientsAsync();
        }

        public byte[] CreateProtocolPacket(byte command, byte subCommand, byte[]? payload = null)
        {
            var packet = new List<byte>();
            packet.AddRange(ProtocolCommands.PROTOCOL_HEADER);
            packet.Add(command);
            packet.Add(subCommand);
            
            if (payload != null && payload.Length > 0)
            {
                packet.AddRange(payload);
            }

            return packet.ToArray();
        }

        private async Task ProcessMessageQueueAsync()
        {
            _logger.LogInformation("消息队列处理任务已启动");

            while (!_cancellationTokenSource!.Token.IsCancellationRequested)
            {
                try
                {
                    // 等待队列中有消息
                    await _queueSemaphore.WaitAsync(_cancellationTokenSource.Token);

                    if (_messageQueue.TryDequeue(out var message))
                    {
                        await ProcessSingleMessageAsync(message);
                    }
                }
                catch (OperationCanceledException)
                {
                    // 正常取消
                    break;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "处理消息队列时发生错误");
                }
            }

            _logger.LogInformation("消息队列处理任务已停止");
        }

        private async Task ProcessSingleMessageAsync(QueuedMessage message)
        {
            try
            {
                _logger.LogDebug("开始处理消息: ClientId={ClientId}, Data={Data}", 
                    message.ClientId, Convert.ToHexString(message.Data));

                var timeout = TimeSpan.FromSeconds(10);
                var success = await _socketServer.SendDataAsync(
                    message.ClientId, 
                    message.Data, 
                    message.ExpectedResponse, 
                    timeout);

                if (success)
                {
                    _logger.LogDebug("消息发送成功: ClientId={ClientId}", message.ClientId);
                    StatusChanged?.Invoke(this, new CommunicationStatusEventArgs(
                        "数据发送成功", $"客户端: {message.ClientId}"));
                }
                else
                {
                    _logger.LogWarning("消息发送失败: ClientId={ClientId}", message.ClientId);
                    StatusChanged?.Invoke(this, new CommunicationStatusEventArgs(
                        "数据发送失败", $"客户端: {message.ClientId}"));
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "处理消息时发生错误: ClientId={ClientId}", message.ClientId);
                StatusChanged?.Invoke(this, new CommunicationStatusEventArgs(
                    "处理消息失败", $"客户端: {message.ClientId}, 错误: {ex.Message}"));
            }
        }

        private static byte[] GetExpectedResponse(byte[] sendData)
        {
            // 根据发送的数据确定期望的回复
            if (sendData.Length >= 4 && 
                sendData[0] == 0x55 && sendData[1] == 0xAA)
            {
                var command = sendData[2];
                var subCommand = sendData[3];

                return command switch
                {
                    0x02 when subCommand == 0x01 => ProtocolCommands.CreateExpectedResponse_20_10(),
                    0x03 when subCommand == 0x01 => ProtocolCommands.CreateExpectedResponse_30_10(),
                    _ => new byte[] { 0x55, 0xAA } // 默认只检查协议头
                };
            }

            return new byte[] { 0x55, 0xAA }; // 默认只检查协议头
        }

        private void OnClientConnected(object? sender, ClientConnectedEventArgs e)
        {
            _logger.LogInformation("客户端已连接: {ClientId} ({IpAddress}:{Port})", 
                e.Client.Id, e.Client.IpAddress, e.Client.Port);
            
            ClientConnected?.Invoke(this, e);
            StatusChanged?.Invoke(this, new CommunicationStatusEventArgs(
                "客户端连接", $"{e.Client.IpAddress}:{e.Client.Port}"));
        }

        private void OnClientDisconnected(object? sender, ClientDisconnectedEventArgs e)
        {
            _logger.LogInformation("客户端已断开: {ClientId} - {Reason}", 
                e.Client.Id, e.Reason);
            
            ClientDisconnected?.Invoke(this, e);
            StatusChanged?.Invoke(this, new CommunicationStatusEventArgs(
                "客户端断开", $"{e.Client.IpAddress}:{e.Client.Port} - {e.Reason}"));
        }

        private void OnDataSent(object? sender, DataSentEventArgs e)
        {
            _logger.LogDebug("数据发送完成: ClientId={ClientId}, Success={Success}", 
                e.ClientId, e.Success);
        }

        private void OnDataReceived(object? sender, DataReceivedEventArgs e)
        {
            _logger.LogDebug("接收到数据: ClientId={ClientId}, Data={Data}", 
                e.ClientId, Convert.ToHexString(e.Data));
        }

        public void Dispose()
        {
            if (!_disposed)
            {
                StopAsync().Wait();
                _queueSemaphore?.Dispose();
                _disposed = true;
            }
        }

        private class QueuedMessage
        {
            public string ClientId { get; set; } = string.Empty;
            public byte[] Data { get; set; } = Array.Empty<byte>();
            public byte[] ExpectedResponse { get; set; } = Array.Empty<byte>();
            public DateTime QueuedAt { get; set; }
        }
    }
}